package cn.zwy.实战;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import cn.zwy.asm.MyClassLoader;
import cn.zwy.service.UserServiceImpl;

public class ASMProxy {

    private Class<?> targetClass;

    public static MyClassLoader classLoader = new MyClassLoader("myClassLoader");

    public Class<?> getTargetClass() {
        return targetClass;
    }

    public void setTargetClass(Class<?> targetClass) {
        this.targetClass = targetClass;
    }

    public Class<?> newProxyClass() throws IOException {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new ASMProxyClassVisitor(cw, targetClass);
        String name = targetClass.getName().replace(".", "/") + ".class";
        ClassReader cr = new ClassReader(targetClass.getClassLoader().getResourceAsStream(name));

        cr.accept(new ClassVisitor(Opcodes.ASM6, cw) {
            @Override
            public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                    String[] exceptions) {
                return new MethodVisitor(Opcodes.ASM6) {
                    @Override
                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end,
                            int index) {
                        if (!"this".equals(name)) {
                            if(ASMProxyClassVisitor.CUR_METHOD_PARAMETER_NAMES.get() == null){
                                ASMProxyClassVisitor.CUR_METHOD_PARAMETER_NAMES.set(new ArrayList<>());
                            }
                            ASMProxyClassVisitor.CUR_METHOD_PARAMETER_NAMES.get().add(name);
                        }
                        super.visitLocalVariable(name, desc, signature, start, end, index);
                    }
                };
            }
        }, 0);
        cr.accept(cv, 0);
        byte[] classByteArr = cw.toByteArray();
        FileOutputStream fos = new FileOutputStream(new File("D:\\bytecode", targetClass.getName() + "_Proxy.class"));
        fos.write(classByteArr, 0, classByteArr.length);
        fos.flush();
        fos.close();
        return classLoader.loadClassByte(targetClass.getName() + "$Proxy", classByteArr);
    }

    public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException {
        ASMProxy asmProxy = new ASMProxy();
        asmProxy.setTargetClass(UserServiceImpl.class);
        UserServiceImpl proxy = (UserServiceImpl) asmProxy.newProxyClass().newInstance();
        // proxy.add();
        proxy.addUser("余超伟", "python@qq.com");
    }
}
